package socket

import (
	log "ac-common-go/glog"
	"ac-common-go/tls"
	"ac-julink/cache"
	"ac-julink/constants"
	"ac-julink/manager"
	"ac-julink/tool/config"
	"ac-julink/tool/data"
	"ac-julink/tool/ymratelimit"
	"fmt"
	"net"
	"runtime"
	"time"
)

var SocketManager *socketAcceptor

// 连接管理信息
type socketAcceptor struct {
	SessionMgr  SessionManager
	tcpListener net.Listener
	tlsListener net.Listener
}

// xiaohong add
func (self *socketAcceptor) StartTls(address, pemPath, keyPath string, context *cache.SyncContext, client *manager.AcRestClient, maxSessionNum int, tokenBucketCapacity, tokenFillIntervalSec int64) {
	cert, err := tls.LoadX509KeyPair(pemPath, keyPath)
	if err != nil {
		log.Errorf("StartTls error:%+v", err)
		return
	}
	var tlsversion uint16
	if data.TlsTurn == 0 {
		tlsversion = tls.VersionTLS10
	} else {
		tlsversion = tls.VersionTLS12
	}
	log.Warningf("Tls version is :%+v", tlsversion)
	tlsConfig := &tls.Config{Certificates: []tls.Certificate{cert}, MinVersion: tlsversion}

	ln, err := tls.Listen("tcp", address, tlsConfig)
	if err != nil {
		log.Errorf("tls.Listen:%+v", err)
		return
	}
	defer ln.Close()

	ratelimter := ymratelimit.NewTokenBucket(time.Second*time.Duration(tokenFillIntervalSec), tokenBucketCapacity)
	log.Warningf("create ratelimiter with tokenFillIntervalSec: %d, tokenBucketCapacity: %d.", tokenFillIntervalSec, tokenBucketCapacity)

	go self.PrintStatusInfo()
	self.tlsListener = ln //端口监听成功,等待客户端接入
	for {
		conn, err := self.tlsListener.Accept()
		if err != nil {
			log.Errorf("listener accept error:%+v", err)
			continue
		}

		if !ratelimter.TakeAvailable() {
			log.Errorf("no token available now, will disconnect this conn")
			if err := conn.Close(); err != nil {
				log.Errorf(fmt.Sprintf("Failed to close conn due to no token available: %v", err))
			}
			continue
		}

		if maxSessionNum > 0 && self.SessionMgr.SessionCount() >= maxSessionNum {
			log.Errorf(fmt.Sprintf("The max session number is %d, will discard this conn.", maxSessionNum))
			if err := conn.Close(); err != nil {
				log.Errorf(fmt.Sprintf("Failed to close conn due to reaching the max session num: %v", err))
			}
			continue
		}

		log.Infof("got a new connection:%s", conn.RemoteAddr())
		go self.onAcceptedTls(conn, context, client)
	}
}

// xiaohong add end
func (self *socketAcceptor) PrintStatusInfo() {
	sleepSec, ok := config.GetConfigIntValue("WGNS", "status_print_sleep")
	if !ok {
		sleepSec = 60
	}
	for {
		newCount, delCount := self.SessionMgr.GetSessionChangeCount()
		log.Warningf("SESSION STATUS===>newses:%d/%ds,delses:%d/%ds,currentses[%d],goroutine[%d]",
			newCount,
			sleepSec,
			delCount,
			sleepSec,
			self.SessionMgr.SessionCount(),
			runtime.NumGoroutine())
		self.SessionMgr.ResetSessionChangeCount()
		time.Sleep(time.Second * time.Duration(sleepSec))
	}
}

// xiaohong add
func (self *socketAcceptor) onAcceptedTls(conn net.Conn, context *cache.SyncContext, client *manager.AcRestClient) {
	ses, err := newSession(conn, time.Now().String(), true) //添加连接会话时间
	if err != nil {
		log.Errorf("session new error: %s,%+v", conn.RemoteAddr(), err)
		return
	}
	wifiId, cryptType, err := ses.AcceptConn(context, client) //解析获取设备的wifiid信息,并回复101消息
	if err != nil {
		log.Errorf("connection accept error: %s,%s,%s", wifiId, conn.RemoteAddr(), err)
		return
	}
	if cryptType == constants.CRYPT_AES_256_CBC {
		ses.CryptType = constants.CRYPT_AES_256_CBC
	}
	//连接加入会话管理组,每个会话关联wifiid
	log.Infof("SessionMgr Add %s:%d to session", wifiId, ses.SessionId())
	self.SessionMgr.Add(ses, ses.SessionId())

	ses.OnClose = func() {
		log.Infof("SessionMgr Remove %s from session", ses.WifiID(), conn.RemoteAddr())
		self.SessionMgr.Remove(ses.SessionId())
	}
	//Tls会话连接建立成功,并启动接收和发送协程
	ses.run(context, client)
}

//xiaohong add end

func NewAcceptor() *socketAcceptor {
	self := &socketAcceptor{
		SessionMgr: NewSessionManager(),
	}

	return self
}
